/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#include "octree.h"
#include "octreenode.h"

#include <algorithm>

namespace Engine
{
	/**********************************************************************************************************/
	Octree::Octree(Octree* p, bool haveStatic)
		:m_numNodes(0)
		,m_parent(p)
		,m_haveStatic(haveStatic)
	{
		//initialize all children to null.
		for ( int i = 0; i < 2; i++ )
		{
			for ( int j = 0; j < 2; j++ )
			{
				for ( int k = 0; k < 2; k++ )
				{
					m_children[ i ][ j ][ k ] = 0;
				}
			}
		}

	}
	/**********************************************************************************************************/
	Octree::~Octree()
	{
		//initialize all children to null.
		for ( int i = 0; i < 2; i++ )
		{
			for ( int j = 0; j < 2; j++ )
			{
				for ( int k = 0; k < 2; k++ )
				{
					if ( m_children[ i ][ j ][ k ] != 0 )
						delete m_children[ i ][ j ][ k ];
				}
			}
		}

	}
	/**********************************************************************************************************/
	void Octree::AddNode( OctreeNode* node )
	{
		m_nodes.push_back( node );
		node->SetOctant( this );

		//update total counts.
		Ref();
	}
	/**********************************************************************************************************/
	void Octree::RemoveNode( OctreeNode* node )
	{
		m_nodes.erase( std::find( m_nodes.begin(), m_nodes.end(), node ) );
		node->SetOctant(0);

		//update total counts.
		UnRef();
	}
	/**********************************************************************************************************/
	bool Octree::IsTwiceSize( const AABB &box ) const
	{
		Vector3<REAL> halfMBoxSize = m_box.GetHalfSize();
		Vector3<REAL> boxSize = box.GetSize();
		return ((boxSize.x <= halfMBoxSize.x) && (boxSize.y <= halfMBoxSize.y) && (boxSize.z <= halfMBoxSize.z));
	}
	/**********************************************************************************************************/
	void Octree::GetChildIndexes(const AABB& box, int* x, int* y, int* z) const
	{
		Vector3<REAL> max = m_box.GetMaximum();
		Vector3<REAL> min = box.GetMinimum();

		Vector3<REAL> center = (m_box.GetMaximum() + m_box.GetMinimum()) * 0.5;

		Vector3<REAL> ncenter = (box.GetMaximum() + box.GetMinimum()) * 0.5;

		if ( ncenter.x > center.x )
			*x = 1;
		else
			*x = 0;

		if ( ncenter.y > center.y )
			*y = 1;
		else
			*y = 0;

		if ( ncenter.z > center.z )
			*z = 1;
		else
			*z = 0;
	}
	/**********************************************************************************************************/
	void Octree::GetCullBounds(AABB* bounds) const
	{
		if(bounds != NULL)
			bounds->SetExtents( m_box.GetMinimum() - m_halfSize, m_box.GetMaximum() + m_halfSize );
	}
	/**********************************************************************************************************/
	void Octree::AddTriangle(const Triangle& tri)
	{
		m_staticGeom[tri.material].push_back(tri.index0);
		m_staticGeom[tri.material].push_back(tri.index1);
		m_staticGeom[tri.material].push_back(tri.index2);
	}
	/**********************************************************************************************************/
	void Octree::UpdateStaticGeom(RenderablesMap* renderables)const
	{
		StaticGeomMap::const_iterator i = m_staticGeom.begin(), e = m_staticGeom.end();
		for(;i != e; ++i)
		{
			RenderablesMap::iterator rend = renderables->find(i->first);
			if(rend != renderables->end())
			{
				rend->second->AddIndex(&i->second[0], i->second.size());
			}
		}
	}
	/**********************************************************************************************************/
	bool Octree::HaveStatic()const
	{
		return m_haveStatic;
	}
	/**********************************************************************************************************/
	void Octree::SetHaveStatic(bool val)
	{
		m_haveStatic = val;
	}
	/**********************************************************************************************************/
}
